using System;
using OpenTK;
namespace Foundry.Engine
{
	public class Transform : BaseObject
	{
		
		private Quaternion rotation;
		private Matrix4 gimble_rotation;
		private Vector3 position;
		private Vector3 scale;
		
	
		[NonSerialized]
		bool changed;
		[NonSerialized]
		private Matrix4 cache;
		[NonSerialized]
		internal Matrix4 abs_cache;
		
		private bool gimbal_lock;
		
		public Transform ParentTransform
		{
			get
			{
				if(this is Scene)
					return null;
				else if(this is Node)
					return (this as Node).Parent as Transform;
				else
					return null;
			}
		}
		
		public Transform ()
		{
			RelativeRotation = Quaternion.Identity;
			RelativePosition = Vector3.Zero;
			RelativeScale = Vector3.One;
		}
		
		/// <summary>
		///Enables or disables Gimbal lock. 
		/// </summary>
		/// <see cref="http://en.wikipedia.org/wiki/Gimbal_lock"/>
		public bool GimbalLock
		{
			set
			{
				GimbalLock = value;
				if(value)
				{
				}
				else
				{
				}
			}
			get
			{
			}
		}
		
		private Matrix4 CreateMatrix()
		{
			var axis = RelativeRotation.ToAxisAngle();
			var rot = Matrix4.CreateFromAxisAngle(axis.Xyz, axis.W);
			var scale = new Matrix4(RelativeScale.X,0,0,RelativePosition.X,
			                        0, RelativeScale.Y, 0, RelativePosition.Y,
			                        0, 0, RelativeScale.Z, RelativePosition.Z,
			                        0,0,0,1);
			return rot * scale;
		}
		
		public virtual Matrix4 Matrix
		{
			get
			{
				if(changed)
				{
					changed = false;
					return cache = CreateMatrix();
				}
				else
					return cache;
			}
		}
		

		public Matrix4 AbsoluteTransform
		{
			get
			{
				return abs_cache;
			}
		}
		
		public void Translate(Vector3 pos)
		{
			RelativePosition += pos;
		}
		
		public void Translate(float x, float y, float z)
		{
			RelativePosition += new Vector3(x, y, z);
		}
		
		public void Scale(Vector3 scale)
		{
			RelativeScale = Vector3.Multiply(RelativeScale, scale);
		}
		
		public void Scale(float x, float y, float z)
		{
			RelativeScale = Vector3.Multiply(RelativeScale, new Vector3(x, y, z));
		}
		
		public void Rotate(Quaternion q)
		{
			RelativeRotation = q * RelativeRotation;
		}
		
		public void Rotate(Vector3 axis, float angle)
		{
			RelativeRotation = Quaternion.FromAxisAngle(axis, angle) * RelativeRotation;
		}
		
		internal Matrix4 GetAbsoluteTransform()
		{
			if(ParentTransform == null)
				return Matrix;
			else
				return ParentTransform.GetAbsoluteTransform() * Matrix;
		}
		
		public Vector3 AbsolutePosition
		{
			get
			{
				if(ParentTransform== null)
					return RelativePosition;
				else
					return ParentTransform.AbsolutePosition + RelativePosition;
			}
		}
		
		public Quaternion AbsoluteRotation
		{
			get
			{
				if(ParentTransform == null)
					return RelativeRotation;
				else
					return RelativeRotation * ParentTransform.AbsoluteRotation;
			}
		}
	
		public Vector3 AbsoluteScale
		{
			get
			{
				if(ParentTransform == null)
					return RelativeScale;
				else
					return Vector3.Multiply(RelativeScale, ParentTransform.AbsoluteScale);
			}
		}
		
		public Vector3 RelativeScale { get { return scale; } set { scale = value; changed = true; } }
		public Quaternion RelativeRotation { get { return rotation; } set { rotation =value; changed = true; } }
		public Vector3 RelativePosition { get { return position; } set{ position = value; changed = true; } }

		
	}
}

